#   Copyright 2008 Wilker Lucio
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import re
import urllib

from musicfinder.common import MusicInfo
from urllib2 import Request, urlopen, HTTPError
from lib.BeautifulSoup import BeautifulSoup

PROVIDER_REPORT_NORESULTS = 0
PROVIDER_REPORT_PARTIAL = 1
PROVIDER_REPORT_ERROR = 2
PROVIDER_REPORT_LENGTH = 3
PROVIDER_REPORT_COMPLETE = 4

class BaseProvider:
    """
    Basic abstract provider, extend this class to create music
    providers
    """
    def request(self, url, data = None, headers = {}, auto_parse = True):
        if data:
            data = urllib.urlencode(data)
        
        headers['User-Agent'] = 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'
        
        request = Request(url, data, headers)
        
        tryn = 0
        
        while(tryn < 3):
            try:
                response = urlopen(request)
            except Exception, e:
                tryn += 1
                
                if tryn == 3:
                    print 'Reach max tries, raising exception'
                    raise e
                
                print 'Error requesting %s, trying again' % url
            else:
                break
        
        if auto_parse:
            return BeautifulSoup(response.read())
        else:
            return response

    def search(self, name, report = (lambda status, data: None)):
        raise NotImplementedError

class MusicParseException(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class PlaylistProvider(BaseProvider):
    url_pattern = re.compile('.*?originallink=([^&]*)', re.I)
    
    def _parse_music(self, box):
        music = MusicInfo()
        
        music.title  = box.find('h2', {'class': 'sr_album-title'}).find('a').contents[0]
        music.artist = urllib.unquote(box.find('div', {'class': 'sr_album-artist clear-all'}).contents[0][8:])
        music.url    = urllib.unquote(self.url_pattern.match(box.find('a', {'class': 'visitsite'})['href']).group(1))
        
        if music.url[-3:].lower() != 'mp3':
            raise MusicParseException('Invalid url music format')
        
        try:
            music.length = box.find('div', {'class': 'sr_metadata'}).contents[0][8:]
        except IndexError:
            music.length = '?'
        
        return music
    
    def search(self, name, report = (lambda status, data: None)):
        nextPage = 1
        total = 0
        musics = []
        
        while nextPage:
            try:
                data = self.request('http://search.playlist.com/tracks/%s/%d' % (urllib.quote(name), nextPage))
            except Exception, e:
                report(self, PROVIDER_REPORT_ERROR)
                raise e
            
            container = data.find('ol', {'class': 'search-list'})
            
            if not container:
                report(self, PROVIDER_REPORT_NORESULTS)
                
                return []
            
            row = []
            
            for box in container.findAll('li'):
                try:
                    music = self._parse_music(box)
                    row.append(music)
                except MusicParseException:
                    pass
            
            if total == 0:
                totalEl = data.find('a', {'rel': 'end'})
                
                if totalEl:
                    total = int(totalEl['href'].split('/')[-1])
                else:
                    total = 1
                
                report(self, PROVIDER_REPORT_LENGTH, total)
            
            report(self, PROVIDER_REPORT_PARTIAL, row)
            
            musics += row
            
            next = data.find('a', {'rel': 'next'})
            
            if next:
                nextPage += 1
            else:
                nextPage = None
        
        report(self, PROVIDER_REPORT_COMPLETE, musics)
        
        return musics

class Mp3TubeProvider(BaseProvider):
    page_pattern = re.compile('.*?pagina=(\d*)', re.I)
    
    def search(self, name, report = (lambda status, data: None)):
        nextPage = 1
        total = 0
        musics = []
        
        while nextPage:
            try:
                url = 'http://www.mp3tube.net/index.php?go=search&pagina=%d&s=&t=%s&tag=' % (nextPage, urllib.quote(name))
                data = self.request(url)
            except Exception, e:
                report(self, PROVIDER_REPORT_ERROR)
                raise e
            
            #get total pages
            if total == 0:
                select = data.find('select')
                total = len(select.contents)
                
                if total == 0:
                    report(self, PROVIDER_REPORT_NORESULTS)
                    
                    return []
                else:
                    report(self, PROVIDER_REPORT_LENGTH, total)
                    
            #parse page
            nextPage = None
            row = []
            
            fonts = data.findAll('font')
            
            for font in fonts:
                if font.string == 'play':
                    music = Mp3TubeInfo()
                    music.length = '?'
                    music.url = 'hidden path'
                    
                    title = font.parent.parent.parent.parent.parent.parent.findAll('td')[1].find('font').find('font').string
                    parts = title.split(' - ')
                    
                    if len(parts) > 1:
                        music.artist = parts[0]
                        music.title = ' - '.join(parts[1:])
                    else:
                        music.artist = title
                        music.title = title
                    
                    music.dataurl = 'http://www.mp3tube.net' + font.parent['href']
                    
                    row.append(music)
                elif font.string == 'Next >>':
                    nextPage = int(self.page_pattern.match(font.parent.parent['href']).group(1))
            
            report(self, PROVIDER_REPORT_PARTIAL, row)
            
            musics += row
        
        report(self, PROVIDER_REPORT_COMPLETE, musics)
        
        return musics

class Mp3TubeInfo(MusicInfo, BaseProvider):
    pattern = re.compile('.*?\?id=([a-z0-9]+).*?', re.I)
    
    def __init__(self, title = "", artist = "", length = "", url = ""):
        self.title = title
        self.artist = artist
        self.length = length
        self.url = url
        self.dataurl = ''
    
    def get_real_path(self):
        data = self.request(self.dataurl)
        
        value = data.find('input', {'name': 'embed'})['value']
        
        id = self.pattern.match(value).group(1)
        
        return 'http://storm.mp3tube.net/d.php?file=%s.tube' % id